package com.beiding.workordersystem.orders.looporder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.beiding.workordersystem.common.beans.MsgSender;
import com.beiding.workordersystem.common.service.BaseService;
import com.beiding.workordersystem.common.standard.E;
import com.beiding.workordersystem.common.utils.*;
import com.beiding.workordersystem.main.utils.Json;
import com.beiding.workordersystem.orders.common.entity.Commission;
import com.beiding.workordersystem.orders.common.entity.FlowUp;
import com.beiding.workordersystem.orders.common.service.CommissionService;
import com.beiding.workordersystem.orders.common.service.FlowUpService;
import com.beiding.workordersystem.orders.looporder.dao.*;
import com.beiding.workordersystem.orders.looporder.entity.*;
import com.beiding.workordersystem.orders.looporder.model.ExpirationDayConfig;
import com.beiding.workordersystem.orders.looporder.model.OrderModel;
import com.beiding.workordersystem.orders.looporder.model.OrderMoon;
import com.beiding.workordersystem.orders.looporder.model.OrderReward;
import com.beiding.workordersystem.orders.looporder.query.CompanyQuery;
import com.beiding.workordersystem.orders.looporder.query.LoopOrderQuery;
import com.beiding.workordersystem.orders.looporder.query.LoopProcessQuery;
import com.beiding.workordersystem.orders.looporder.service.CompanyService;
import com.beiding.workordersystem.orders.looporder.service.OrderService;
import com.beiding.workordersystem.orders.product.entity.Product;
import com.beiding.workordersystem.orders.product.service.ProductService;
import com.beiding.workordersystem.system.entity.UserEntity;
import com.beiding.workordersystem.system.service.UserService;
import com.beiding.workordersystem.system.service.VariableService;
import com.gitee.beiding.timer.annotation.AspectHandler;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends BaseService implements OrderService {

    @Autowired
    private FlowUpService flowUpService;

    @Autowired
    private LoopOrderDao loopOrderDao;

    @Autowired
    private CompanyDao companyDao;

    @Autowired
    private UserService userService;

    @Autowired
    private LoopProcessDao loopProcessDao;

    @Autowired
    private ProcessCommissionDao processCommissionDao;

    @Autowired
    private OrderProductDao orderProductDao;

    @Override
    public IPage<LoopOrder> page(IPage toIPage, LoopOrderQuery q) {

        LambdaQueryWrapper<LoopOrder> query = QueryUtils.getQuery(LoopOrder.class);
        List<String> list = handleCompanyQuery(q);
        if (list != null) {
            if (isEmpty(list)) {
                return toIPage;
            } else {
                query.in(LoopOrder::getCompanyId, list);
            }
        }
        handleOrderQuery(query, q);

        IPage<LoopOrder> loopOrderIPage = (IPage<LoopOrder>) loopOrderDao.selectPage(toIPage, query);

        if (notEmpty(loopOrderIPage.getRecords())) {
            for (LoopOrder record : loopOrderIPage.getRecords()) {
                record.setCompany(companyDao.selectById(record.getCompanyId()));
            }
        }

        return loopOrderIPage;

    }

    private void handleOrderQuery(LambdaQueryWrapper<LoopOrder> query, LoopOrderQuery q) {

        if (q.getOnlyMine()) {
            query.eq(LoopOrder::getPrincipalId, MySecurityUtils.currentCredentials().getUserId());
        } else if (q.getOnlyCreator()) {
            query.eq(LoopOrder::getCreatorId, MySecurityUtils.currentCredentials().getUserId());
            if (notEmpty(q.getStatuses())) {
                query.in(LoopOrder::getStatus, Arrays.asList(q.getStatuses()));
            }
        } else {
            if (isEmpty(q.getStatuses())) {
                query.notIn(LoopOrder::getStatus, Arrays.asList(0, 1));
            } else {
                query.in(LoopOrder::getStatus, Arrays.asList(q.getStatuses()));
            }
        }

        query.gt(notEmpty(q.getCreateTimeFrom()), LoopOrder::getCreateTime, q.getCreateTimeFrom());
        query.lt(notEmpty(q.getCreateTimeTo()), LoopOrder::getCreateTime, q.getCreateTimeTo());

    }

    private List<String> handleCompanyQuery(CompanyQuery query) {

        boolean hasCondition = false;


        LambdaQueryWrapper<Company> companyLambdaQueryWrapper = QueryUtils.getQuery(Company.class);

        if (notEmpty(query.getTaxNature())) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getTaxNature, query.getTaxNature());
        }

        if (notEmpty(query.getRank())) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getRank, query.getRank());
        }

        if (notEmpty(query.getAccountType())) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getAccountType, query.getAccountType());
        }

        if (notEmpty(query.getCompanyName())) {
            hasCondition = true;
            companyLambdaQueryWrapper.like(Company::getName, query.getCompanyName());
        }

        if (query.getHasBank()) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getHasBank, query.getHasBank());
        }

        if (query.getHasSocialSecurity()) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getHasSocialSecurity, query.getHasSocialSecurity());
        }

        if (query.getHasAccumulationFundAccount()) {
            hasCondition = true;
            companyLambdaQueryWrapper.eq(Company::getHasAccumulationFundAccount, query.getHasAccumulationFundAccount());
        }

        if (hasCondition) {
            List<Company> companies = companyDao.selectList(companyLambdaQueryWrapper);
            return companies.stream().map(Company::getId).collect(Collectors.toList());
        } else {
            return null;
        }

    }

    @Autowired
    private CompanyService companyService;

    @Override
    @Transactional
    public void save(Company company, LoopOrder order) {

        if (order.getId() != null) {
            LoopOrder loopOrder = loopOrderDao.selectById(order.getId());
            E.notNull(loopOrder, "更新的工单不存在");

            //管理员可以强制
            if (!MySecurityUtils.currentCredentials().hasAuthority("loopOrder_update_forced")) {
                E.isTrue(loopOrder.getStatus().equals(0) || loopOrder.getStatus().equals(1), "当前状态不可编辑");
            }
        }
        company.setDeal(false);
        companyService.save(company);
        saveOrder(order, company.getId());
    }

    private SimpleDateFormat easyDateFomat = new SimpleDateFormat("yyyy年MM月dd日");

    private void checkFirst(LoopOrder loopOrder, String msg) {

        String json = loopOrder.getExpirationDayConfig();
        Date start = loopOrder.getServiceStartTime();
        ExpirationDayConfig config = null;
        try {
            config = Json.parse(json, ExpirationDayConfig.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        Integer day = DateCalculator.getDayOfMoonCurrent();

        Integer moonOfYearCurrent = DateCalculator.getMoonOfYearCurrent();

        Map<Integer, Integer> rules = config.rulesToMap();

        Integer checkDay = config.getDefaultDay();

        if (rules != null) {
            Integer integer = rules.get(moonOfYearCurrent);
            if (integer != null) {
                checkDay = integer;
            }
        }

        Date date = new Date();
        Integer moonBiggerThan = DateCalculator.moonBiggerThan(date, start);

        if (moonBiggerThan > 2) {
            E.error(msg.replace("${currentDay}", easyDateFomat.format(date)).replace("${fristDay}", dateFormatShow.format(loopOrder.getServiceStartTime())));
        } else if (moonBiggerThan == 1) {
            if (day > checkDay) {
                E.error(msg.replace("${currentDay}", easyDateFomat.format(date)).replace("${fristDay}", dateFormatShow.format(loopOrder.getServiceStartTime())));
            }
        }
    }

    @Autowired
    private ProductService productService;

    //在保存以后不需要创建自动过期的任务,而是在进行相关操作的时候才进行过时
    @Transactional
    private void saveOrder(LoopOrder order, String companyId) {

        List<OrderProduct> orderProducts = order.getProducts();

        Double fee = 0D;

        if (notEmpty(orderProducts)) {
            for (OrderProduct orderProduct : orderProducts) {
                Product product = orderProduct.getProduct();
                product = productService.findById(product.getId());
                E.notNull(product, "未找到关联的产品");
                orderProduct.setOrderId(order.getId());
                orderProduct.setProductId(product.getId());
                if (orderProduct.getRealPrice() == null) {
                    orderProduct.setRealPrice(product.getSuggestPrice());
                }
                if (orderProduct.getNumber() == null) {
                    orderProduct.setNumber(1);
                }
                fee += orderProduct.getNumber()*orderProduct.getRealPrice();
            }
        }

        //后台重新核算费用
        order.setFee(fee);

        if (fillId(order)) {

            checkFirst(order, "根据截止日规则,当前时间(${currentDay})已经无法处理首次(${fristDay})记账报税任务,请重新选择服务开始时间");

            order.setCreateTime(new Date());
            order.setCreatorId(MySecurityUtils.currentCredentials().getUserId());

            //唯一绑定
            order.setCompanyId(companyId);
            if (System.currentTimeMillis() > order.getServiceEndTime().getTime()) {
                order.setStatus(6);
            } else {
                order.setStatus(0);
            }
            loopOrderDao.insert(order);

        } else {
            loopOrderDao.updateById(order);
            orderProductDao.delete(QueryUtils.getQuery(OrderProduct.class).eq(OrderProduct::getOrderId, order.getId()));
        }

        if (notEmpty(orderProducts)) {
            for (OrderProduct orderProduct : orderProducts) {
                orderProductDao.insert(orderProduct);
            }
        }



    }


    @Override
    @Transactional
    public void delete(String[] ids) {
        long currentTimeMillis = System.currentTimeMillis();
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.isTrue(loopOrder.getStatus().equals(0) || currentTimeMillis > loopOrder.getServiceEndTime().getTime(), "当前状态不可删除");
            loopOrderDao.deleteById(id);
            Company company = companyDao.selectById(loopOrder.getCompanyId());
            if (!company.getDeal()) {
                companyDao.deleteById(loopOrder.getCompanyId());
            }
        }
    }

    @Override
    @Transactional
    public void submit(String[] ids) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            E.isTrue(loopOrder.getStatus().equals(0) || loopOrder.getStatus().equals(1), "当前状态不可提交");
            loopOrder.setStatus(2);
            loopOrderDao.updateById(loopOrder);
        }
    }

    @Override
    @Transactional
    public void pass(String[] ids) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            E.isTrue(loopOrder.getStatus().equals(2), "当前状态不支持该操作");
            loopOrder.setStatus(3);
            loopOrder.setMainSatrapId(MySecurityUtils.currentCredentials().getUserId());

            loopOrderDao.updateById(loopOrder);

        }
    }

    @Override
    @Transactional
    public void refuse(String[] ids, String reason) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            E.isTrue(loopOrder.getStatus().equals(2), "当前状态不支持该操作");
            loopOrder.setStatus(1);
            loopOrder.setRefuseReason(reason);
            loopOrderDao.updateById(loopOrder);

        }
    }

    @Override
    @Transactional
    public void start(String[] ids) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            E.isTrue(loopOrder.getStatus().equals(4), "当前状态不支持该操作");
            loopOrder.setStatus(5);
            start(loopOrder);
            loopOrderDao.updateById(loopOrder);
        }
    }

    @Override
    @Transactional
    public void designate(List<LoopProcess> list) {
        LoopProcess process = list.get(0);

        String orderId = process.getOrderId();
        String principalId = process.getPrincipalId();


        LoopOrder loopOrder = loopOrderDao.selectOne(QueryUtils.getQuery(LoopOrder.class).eq(LoopOrder::getId, orderId));
        E.notNull(loopOrder, "工单不存在");
        E.isTrue(userService.existById(principalId), "负责人不存在");

        loopOrder.setStatus(4);
        loopOrder.setPrincipalId(principalId);
        loopOrderDao.updateById(loopOrder);
        loopProcessDao.delete(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getOrderId, orderId));
        for (LoopProcess loopProcess : list) {
            fillId(loopProcess);
            loopProcessDao.insert(loopProcess);
            List<ProcessCommission> commissions = loopProcess.getCommissions();
            if (commissions != null) {
                for (ProcessCommission commission : commissions) {
                    fillId(commission);
                    processCommissionDao.insert(commission);
                }
            }
        }
    }


    @Override
    public LoopOrder details(String id) {
        LoopOrder loopOrder = loopOrderDao.selectById(id);
        if (loopOrder != null) {
            List<LoopProcess> list = loopProcessDao.selectList(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getOrderId, id).isNull(LoopProcess::getTemplateId));
            loopOrder.setProcesses(list);

            if (list.size() > 0) {
                LoopProcess process = list.get(0);
                process.setSatrapName(userService.getById(process.getSatrapId()).getName());
                UserEntity userEntity = userService.getById(process.getPrincipalId());
                for (LoopProcess loopProcess : list) {
                    loopProcess.setPrincipal(userEntity);
                    loopProcess.setCommissions(processCommissionDao.selectList(QueryUtils.getQuery(ProcessCommission.class).eq(ProcessCommission::getProcessId, loopProcess.getId())));
                }
            }

            UserEntity userEntity = userService.getById(loopOrder.getCreatorId());
            loopOrder.setCreator(userEntity);
            Company company = companyDao.selectById(loopOrder.getCompanyId());
            loopOrder.setCompany(company);

            List<OrderProduct> orderProducts = orderProductDao.selectList(QueryUtils.getQuery(OrderProduct.class).eq(OrderProduct::getOrderId, id));

            for (OrderProduct product : orderProducts) {
                Product p = productService.findById(product.getProductId());
                if (notEmpty(p)) {
                    product.setProduct(p);
                } else {
                    p = new Product();
                    p.setName("*已失效*");
                    product.setProduct(p);
                }
            }

            loopOrder.setProducts(orderProducts);


        }
        return loopOrder;
    }

    @Override
    public List<LoopProcess> task(String id) {
        List<LoopProcess> loopProcesses = loopProcessDao.selectList(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getTemplateId, id).ne(LoopProcess::getStatus, 0).lt(LoopProcess::getCheckTime, new Date()));
        if (notEmpty(loopProcesses)) {
            for (LoopProcess loopProcess : loopProcesses) {
                List<FlowUp> list = flowUpService.list(loopProcess.getId());
                loopProcess.setFlowUps(list);
            }
        }

        return loopProcesses;
    }

    @Override
    public void accept(String[] ids) {

        for (String id : ids) {
            LoopProcess loopProcess = loopProcessDao.selectById(id);
            E.notNull(loopProcess, "工序不存在");
            E.isTrue(loopProcess.getStatus() == 0, "该状态不可受理");
            loopProcess.setStatus(1);
            loopProcessDao.updateById(loopProcess);
        }

    }

    @Autowired
    private CommissionService commissionService;

    @Override
    public void finish(String[] ids, Boolean sendMsg) {

        for (String id : ids) {
            LoopProcess orderProcess = loopProcessDao.selectById(id);
            E.notNull(orderProcess, "工序不存在");
            E.isTrue(orderProcess.getStatus() == 1, "该状态不可受理");
            orderProcess.setStatus(3);
            loopProcessDao.updateById(orderProcess);

            Commission commission = new Commission();

            commission.setBigType(orderProcess.getBigType());
            commission.setWork(orderProcess.getWork());
            commission.setWorkDetails(orderProcess.getWorkDetails());
            commission.setBusinessType(orderProcess.getBusinessType());
            commission.setUserId(orderProcess.getPrincipalId());
            commission.setSatrapId(orderProcess.getSatrapId());

            //计算提成
            LoopOrder loopOrder = loopOrderDao.selectById(orderProcess.getOrderId());
            loopOrder.setCompany(companyDao.selectById(loopOrder.getCompanyId()));
            commission(loopOrder, orderProcess);

            commission.setValue(orderProcess.getCommissionFee());
            commission.setSatrapValue(orderProcess.getCommissionFee());

            commission.setCompleteTime(new Date());
            //完结之后添加提成
            commissionService.save(commission);

            if (sendMsg) {

                //给所有联系人发送工单完结的短信

                Company company = companyDao.selectById(loopOrder.getCompanyId());

                String legalPersonPhone = company.getLegalPersonPhone();
                String[] split = legalPersonPhone.split("||");

                for (String s : split) {
                    Map map = Json.parseToMap(s);
                    String name = (String) map.get("name");
                    String phone = (String) map.get("phone");

                    Map<String, String> params = new HashMap<>();
                    params.put("name", name);

                    //生成20位随机码并绑定工序id
                    String code = RandomUtils.createRandomString(19);
                    variableService.set(code, orderProcess.getId());

                    //最后一位标记工单类型,如果是0表示普通工单,1则表示记账报税
                    params.put("code", code + "1");

                    sender.send(phone, "SMS_184206018", params);
                    //两天有效
                    ApplicationUtils.get(this).removeDetailsCode(code, 48 * 60 * 60 * 1000);
                }

            }

        }

    }



    @Autowired
    private MsgSender sender;

    @AspectHandler
    public void removeDetailsCode(String key, long time) {
        variableService.set(key, null);
    }

    @Autowired
    private VariableService variableService;


    @Override
    public IPage myTask(IPage toIPage, LoopProcessQuery query) {
        LambdaQueryWrapper<LoopProcess> wrapper = QueryUtils.getQuery(LoopProcess.class).isNotNull(LoopProcess::getTemplateId).eq(LoopProcess::getPrincipalId, MySecurityUtils.currentCredentials().getUserId()).lt(LoopProcess::getCheckTime, new Date());

        wrapper.in(notEmpty(query.getStatuses()), LoopProcess::getStatus, query.getStatuses());
     /*   wrapper.gt(notEmpty(query.getFrom()), LoopProcess::getCheckTime, query.getFrom());
        wrapper.lt(notEmpty(query.getTo()), LoopProcess::getCheckTime, query.getTo());
*/
        return (IPage<LoopProcess>) loopProcessDao.selectPage(toIPage, wrapper);
    }

    //
    @Override
    public void postpone(String id, Date endTime) {
        LoopOrder loopOrder = loopOrderDao.selectById(id);
        E.notNull(loopOrder, "工单未指派");
        E.isTrue(loopOrder.getStatus() == 6, "状态不满足预期");
        List<LoopProcess> list = loopProcessDao.selectList(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getOrderId, id).isNull(LoopProcess::getTemplateId));
        GregorianCalendar gc = new GregorianCalendar();

        Date startTime = loopOrder.getServiceStartTime();

        //将开始时间变更为结束时间
        loopOrder.setServiceStartTime(loopOrder.getServiceEndTime());
        loopOrder.setServiceEndTime(endTime);
        startProcess(loopOrder);
        loopOrder.setServiceStartTime(startTime);

        loopOrder.setStatus(5);
        loopOrderDao.updateById(loopOrder);
    }

    @Override
    @Transactional
    public void endCooperation(String[] ids, String r) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            E.isTrue(loopOrder.getStatus() == 6, "状态不满足预期");
            loopOrder.setEndCooperationReason(r);
            loopOrder.setStatus(7);
            loopOrderDao.updateById(loopOrder);
        }
    }

    @Override
    public void toDeal(String[] ids) {
        for (String id : ids) {
            LoopOrder loopOrder = loopOrderDao.selectById(id);
            E.notNull(loopOrder, "工单不存在");
            Company company = companyDao.selectById(loopOrder.getCompanyId());
            company.setDeal(true);
            companyDao.updateById(company);
            loopOrder.setCompanyToDeal(true);
            loopOrderDao.updateById(loopOrder);
        }
    }

    //
    private void start(LoopOrder loopOrder) {

        try {
            checkFirst(loopOrder, "根据截止日规则,当前时间(${currentDay})已经无法处理首次(${fristDay})记账报税任务,该工单将被变更为过期状态");
        } catch (E e) {
            Runner.exe(() -> {
                loopOrder.setStatus(8);
                loopOrderDao.updateById(loopOrder);
            });

            //重新抛出
            throw e;
        }

        /*List<LoopProcess> list = loopProcessDao.selectList(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getOrderId, loopOrder.getId()));
        GregorianCalendar gc = new GregorianCalendar();
        for (LoopProcess process : list) {
            startProcess(loopOrder, gc, process);
        }
        */
    }


    @AspectHandler
    public void loopProcessOverdue(String id, Date date) {
        LoopProcess loopProcess = loopProcessDao.selectById(id);
        if (loopProcess != null) {
            if (loopProcess.getStatus() == 0) {
                loopProcess.setStatus(4);
                loopProcessDao.updateById(loopProcess);
            }
        }
    }


    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");

    private SimpleDateFormat dateFormatShow = new SimpleDateFormat("yyyy年MM月");


    @Override
    public OrderModel statistics(Date start, Date to) {
        //必须给出一个有效的区间
        if (start != null && to != null) {
            E.isTrue(to.getTime() >= start.getTime(), "无效时间区间");
        } else if (start == null && to == null) {
            to = new Date();
            start = DateCalculator.addYear(to, -1);
        } else {
            if (start == null) {
                start = DateCalculator.addYear(to, -1);
            } else {
                to = DateCalculator.addYear(start, 1);
            }
        }

        Map<String, List<LoopOrder>> map = new HashMap<>();

        List<String> head = new ArrayList<>();

        //从开始时间
        Date t = start;
        while (t.getTime() <= to.getTime()) {

            //格式化时间
            String format = dateFormat.format(t);

            final Date tt = t;

            LambdaQueryWrapper<LoopOrder> wrapper = QueryUtils.getQuery(LoopOrder.class).likeRight(LoopOrder::getServiceStartTime, format).or().likeRight(LoopOrder::getServiceEndTime, format)
                    .or(q -> {
                        return q.gt(LoopOrder::getServiceEndTime, tt).lt(LoopOrder::getServiceStartTime, tt);
                    });

            List<LoopOrder> loopOrders = loopOrderDao.selectList(wrapper);

            String show = dateFormatShow.format(t);

            head.add(show);

            map.put(show, loopOrders);

            //增加一个月份
            t = DateCalculator.addMoon(t, 1);
        }


        OrderReward rewards = new OrderReward();

        OrderModel orderModel = new OrderModel();

        orderModel.setHead(head);

        Map<String, Double> valueMap = new HashMap<>();


        Map<String, OrderMoon> moons = new HashMap<>();

        map.forEach((k, v) -> {
            double sum = 0;
            for (LoopOrder order : v) {
                //计算费用
                Double value = valueMap.computeIfAbsent(order.getId(), tmp -> {
                    int num = moonNum(dateFormat.format(order.getServiceStartTime()), dateFormat.format(order.getServiceEndTime()));
                    return order.getFee() / num;
                });
                sum += value;
            }
            OrderMoon moon = new OrderMoon();
            moon.setSum(sum);
            moons.put(k, moon);
        });

        rewards.setMoons(moons);

        orderModel.setReward(rewards);

        return orderModel;
    }


    private int moonNum(String start, String end) {
        String[] split = start.split("-");
        Integer startYear = Integer.valueOf(split[0]);
        Integer startMoon = Integer.valueOf(split[1]);

        split = end.split("-");

        Integer endYear = Integer.valueOf(split[0]);
        Integer endMoon = Integer.valueOf(split[1]);

        int endAll = endYear * 12 + endMoon;
        int startAll = startYear * 12 + startMoon;

        return 1 + endAll - startAll;
    }

    @Override
    @Transactional
    public void activeTaxCategoriesAndCycle(String orderId, List<String> taxCategoriesAndCycles) {

        LoopOrder loopOrder = loopOrderDao.selectById(orderId);
        E.notNull(loopOrder, "工单不存在,或已被删除");

        String activeTaxCategoriesAndCycle = loopOrder.getActiveTaxCategoriesAndCycle();

        if (activeTaxCategoriesAndCycle == null) {
            activeTaxCategoriesAndCycle = "";
        }

        try {
            if (isEmpty(activeTaxCategoriesAndCycle)) {
                checkFirst(loopOrder, "根据截止日规则,当前时间(${currentDay})已经无法处理首次(${fristDay})记账报税任务,激活记账报税失败,由于该工单尚未激活任何税种和周期将被变更为超时状态");
            } else {
                checkFirst(loopOrder, "根据截止日规则,当前时间(${currentDay})已经无法处理首次(${fristDay})记账报税任务,激活记账报税失败");
            }
        } catch (E e) {
            if
            (isEmpty(activeTaxCategoriesAndCycle)) {
                Runner.exe(() -> {
                    loopOrder.setStatus(8);
                    loopOrderDao.updateById(loopOrder);
                });
            }
            throw e;
        }

        Set<String> atccs = new HashSet<>();
        String[] split = activeTaxCategoriesAndCycle.split(",");
        for (String s : split) {
            if (!s.trim().equals("")) {
                atccs.add(s);
            }
        }
        if (notEmpty(taxCategoriesAndCycles)) {
            for (String s : taxCategoriesAndCycles) {
                if (!s.trim().equals("")) {
                    atccs.add(s);
                }
            }
        }

        loopOrder.setActiveTaxCategoriesAndCycle(Joiner.on(",").join(atccs));
        loopOrderDao.updateById(loopOrder);
        startProcess(loopOrder);

    }

    @Override
    public LoopOrder findById(String orderId) {
        return loopOrderDao.selectById(orderId);
    }


    private void startProcess(LoopOrder loopOrder) {

        boolean addMoon = false;
        boolean addQuarter = false;
        Set<String> atccs = Sets.newHashSet(loopOrder.getActiveTaxCategoriesAndCycle().split(","));

        for (String atcc : atccs) {
            if (atcc.endsWith("-月报")) {
                addMoon = true;
            } else if (atcc.endsWith("-季报")) {
                addQuarter = true;
            }
        }
        Integer type;
        type = null;
        if (addMoon) {
            type = 0;
        } else {
            if (addQuarter) {
                type = 1;
            }
        }

        if (type != null) {
            createTask(loopOrder, type);
        }

    }


    /*

        如果季报和月报同在,那么每隔两个月报将出现一个季报
        例如:  月月季月月季月月季月月季

        即:如果次数是3的整倍数时创建为季报
            times%3==0

     */


    private void createTask(LoopOrder loopOrder, int type) {


        Integer moonBiggerThan = DateCalculator.moonBiggerThan(loopOrder.getServiceEndTime(), loopOrder.getServiceStartTime());

        List<LoopProcess> loopProcesses = loopProcessDao.selectList(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getOrderId, loopOrder.getId()).isNull(LoopProcess::getTemplateId));

        Map<Integer, Integer> map = loopOrder.getExpirationDayConfigEntity().rulesToMap();
        Integer dayOfMoonCurrent = DateCalculator.getDayOfMoonCurrent();
        Integer moonOfYearCurrent = DateCalculator.getMoonOfYearCurrent();
        Integer integer = map.get(moonBiggerThan);
        int i = 0;
        if (dayOfMoonCurrent > integer) {
            i = 1;
        }

        int n = 0;

        for (; i < moonBiggerThan + 1; i++) {

            n++;
            if (type == 0 || (type == 1 && n % 3 == 0)) {

                //创建工单任务
                Date check = DateCalculator.addMoon(loopOrder.getServiceStartTime(), i);
                for (LoopProcess process : loopProcesses) {

                    if (!loopProcessDao.exist(QueryUtils.getQuery(LoopProcess.class).eq(LoopProcess::getTemplateId, process.getId()).eq(LoopProcess::getCheckTime, check))) {
                        LoopProcess loopProcess = new LoopProcess();
                        BeanUtils.copyProperties(process, loopProcess);
                        loopProcess.setCheckTime(check);
                        Integer moonOfYear = DateCalculator.getMoonOfYear(check);
                        loopProcess.setExpirationTime(DateCalculator.createDate(DateCalculator.getYear(check), moonOfYear, map.get(moonOfYear)));
                        loopProcess.setTemplateId(process.getId());
                        loopProcess.setId(createId());
                        loopProcessDao.insert(loopProcess);
                    }
                }
            }
        }

    }

    private void commission(LoopOrder order, LoopProcess process) {

        Company company = order.getCompany();

        String activeTaxCategoriesAndCycle = order.getActiveTaxCategoriesAndCycle();

        String[] split = activeTaxCategoriesAndCycle.split(",");


        //找到提成列表
        List<ProcessCommission> commissionList = processCommissionDao.selectList(QueryUtils.getQuery(ProcessCommission.class).eq(ProcessCommission::getProcessId, process.getId()));

        Map<String, ProcessCommission> stringProcessCommissionHashMap = new HashMap<>();

        for (ProcessCommission processCommission : commissionList) {
            String key = processCommission.getTaxCategories() + "-" + processCommission.getCycle() + "-" + processCommission.getTaxNature();
            stringProcessCommissionHashMap.put(key, processCommission);
        }

        //再次遍历一遍列表,如果存在季报提成就移除月报提成
        for (ProcessCommission processCommission : commissionList) {
            if ("季报".equals(processCommission.getCycle())) {
                String key = processCommission.getTaxCategories() + "-月报-" + processCommission.getTaxNature();
                stringProcessCommissionHashMap.remove(key);
            }
        }

        double cf = 0;
        double scf = 0;
        for (String s : split) {
            String key = s + "-" + company.getTaxNature();
            ProcessCommission processCommission = stringProcessCommissionHashMap.get(key);
            if (processCommission != null) {
                cf += processCommission.getCommissionFee();
                scf += processCommission.getSatrapCommissionFee();
            }
        }

        process.setCommissionFee(cf);
        process.setCommissionFee(scf);

    }


/*
    private void startProcess(LoopOrder loopOrder, GregorianCalendar gc, LoopProcess process) {

        Date serviceStartTime = loopOrder.getServiceStartTime();
        long end = loopOrder.getServiceEndTime().getTime();
        int t = 0;
        long currentTimeMillis = System.currentTimeMillis();
        while (true) {
            gc.setTime(serviceStartTime);
            t++;
            gc.add(unit, t * base);
            Date time = gc.getTime();
            if (time.getTime() > end) {
                break;
            }
            LoopProcess copy = MyBeanUtils.copy(process, LoopProcess.class);
            copy.setId(null);
            fillId(copy);
            copy.setCheckTime(time);
            copy.setTemplateId(process.getId());
            fillId(copy);

            gc.add(Calendar.DAY_OF_YEAR, copy.getMaxTime());

            time = gc.getTime();
            boolean ov = false;
            if (time.getTime() > currentTimeMillis) {
                copy.setStatus(4);
                ov = true;
            } else {
                copy.setStatus(0);
            }
            loopProcessDao.insert(copy);

            //添加定时任务
            if (ov) {
                loopProcessOverdue(copy.getId(), time);
            }

        }

    }


    @AspectHandler
    public void loopOrderOverdue(String id, Date date) {

        LoopOrder loopOrder = loopOrderDao.selectById(id);
        if (loopOrder != null) {
            if (System.currentTimeMillis() + 3600 * 1000 > loopOrder.getServiceEndTime().getTime()) {
                loopOrder.setStatus(6);
                loopOrderDao.updateById(loopOrder);
            }
        }
    }*/

}
